package com.dhl.fin.api.service;

import cn.hutool.Hutool;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.dhl.fin.api.common.exception.BusinessException;
import com.dhl.fin.api.common.service.CommonService;
import com.dhl.fin.api.common.util.CollectorUtil;
import com.dhl.fin.api.common.util.ObjectUtil;
import com.dhl.fin.api.common.util.WebUtil;
import com.dhl.fin.api.constant.RemindConstant;
import com.dhl.fin.api.domain.MensesRemindTask;
import com.dhl.fin.api.domain.RemindTask;
import com.dhl.fin.api.domain.RemindType;
import com.dhl.fin.api.dto.MensesCalenderDTO;
import com.dhl.fin.api.dto.MensesCalenderMonthDataDTO;
import com.dhl.fin.api.dto.MensesCalenderNextTimeRespDTO;
import com.dhl.fin.api.dto.NextTimeDTO;
import com.dhl.fin.api.enums.MensesTypeEnum;
import com.dhl.fin.api.enums.RemindCycleTypeEnum;
import com.dhl.fin.api.enums.RemindTypeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author CuiJianbo
 * @since 2025/5/19
 */
@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class MensesRemindTaskService extends CommonService<MensesRemindTask> {

    @Autowired
    private RemindTypeService remindTypeService;

    @Autowired
    private ExtraJobCronService extraJobCronService;

    public MensesCalenderNextTimeRespDTO getMensesCalenderData(MensesRemindTask mensesRemindTask) throws Exception {
        Date nextMensesDate = mensesRemindTask.getMensesLastDateOne();
        List<MensesCalenderMonthDataDTO> calenderMonthDataDTOS = new ArrayList<>();
        Map<String, MensesCalenderDTO> calenderDTOMap = findMensesTipDateCalenderData(mensesRemindTask);

        for (int i = 0; i < 3; i++) {
            Date d = DateUtil.offsetMonth(nextMensesDate, i);
            int[] monthDayArray = getMonthDayArray(d);
            MensesCalenderMonthDataDTO mensesCalenderMonthDataDTO = changeToMensesCalender(monthDayArray, calenderDTOMap, d);
            analysisRemindDay(mensesRemindTask, mensesCalenderMonthDataDTO.getMensesCalenderDTOS());
            calenderMonthDataDTOS.add(mensesCalenderMonthDataDTO);
        }
        List<NextTimeDTO> nextTimes = calenderMonthDataDTOS.stream()
                .map(MensesCalenderMonthDataDTO::getMensesCalenderDTOS)
                .flatMap(Collection::stream)
                .filter(p -> ObjectUtil.notNull(p.getIsRemind()))
                .filter(MensesCalenderDTO::getIsRemind)
                .map(MensesCalenderDTO::changeToNextTimeDTO)
                .limit(5).collect(Collectors.toList());

        return new MensesCalenderNextTimeRespDTO(nextTimes, calenderMonthDataDTOS);
    }

    public MensesCalenderNextTimeRespDTO getMensesCalender(MensesRemindTask mensesRemindTask) throws Exception {

        Date nextMensesDate = mensesRemindTask.getMensesLastDateOne();
        Date lastTwoDate = mensesRemindTask.getMensesLastDateTwo();
        int keepDateNum = mensesRemindTask.getMensesKeepDateNum();
        int daysOfMensesDuration = (int) DateUtil.betweenDay(nextMensesDate, lastTwoDate, true);
        Date nextNextMensesDate = DateUtil.offsetDay(nextMensesDate, daysOfMensesDuration);
        Date mensesDate = DateUtil.offsetDay(nextMensesDate, -daysOfMensesDuration);
        int[] nextMonthDayArray = getMonthDayArray(nextMensesDate);
        int[] nextNextMonthDayArray = getMonthDayArray(nextNextMensesDate);
        List<MensesCalenderDTO> nextMensesCalenderDTOS = new ArrayList<>();
        List<MensesCalenderDTO> mensesCalenderDTOS = new ArrayList<>();


        //添加排卵日和月经日
        getMensesCalenderDTO(daysOfMensesDuration, keepDateNum, mensesDate, null, nextMonthDayArray, null, mensesCalenderDTOS);
        getMensesCalenderDTO(daysOfMensesDuration, keepDateNum, nextMensesDate, nextMonthDayArray, nextNextMonthDayArray, mensesCalenderDTOS, nextMensesCalenderDTOS);
        getMensesCalenderDTO(daysOfMensesDuration, keepDateNum, nextNextMensesDate, nextNextMonthDayArray, null, nextMensesCalenderDTOS, null);

        //添加安全日和默认日
        fillSafeDaysAndDefaultDay(nextMonthDayArray, mensesCalenderDTOS, nextMensesDate);
        fillSafeDaysAndDefaultDay(nextNextMonthDayArray, nextMensesCalenderDTOS, nextNextMensesDate);

        mensesCalenderDTOS = new LinkedList<>(mensesCalenderDTOS.stream().collect(Collectors.toMap(MensesCalenderDTO::getIndex, Function.identity(), (x, y) -> x)).values());
        nextMensesCalenderDTOS = new LinkedList<>(nextMensesCalenderDTOS.stream().collect(Collectors.toMap(MensesCalenderDTO::getIndex, Function.identity(), (x, y) -> x)).values());

        //添加提醒标记
        analysisRemindDay(mensesRemindTask, mensesCalenderDTOS);
        analysisRemindDay(mensesRemindTask, nextMensesCalenderDTOS);

        MensesCalenderMonthDataDTO monthDataDTO1 = MensesCalenderMonthDataDTO.getInstance(nextMensesDate, mensesCalenderDTOS);
        MensesCalenderMonthDataDTO monthDataDTO2 = MensesCalenderMonthDataDTO.getInstance(nextNextMensesDate, nextMensesCalenderDTOS);
        List<MensesCalenderMonthDataDTO> calenderMonthDataDTOS = CollectorUtil.toList(monthDataDTO1, monthDataDTO2);

        List<NextTimeDTO> nextTimeDTOList1 = getNextTimeDTOList(mensesCalenderDTOS);
        List<NextTimeDTO> nextTimeDTOList2 = getNextTimeDTOList(nextMensesCalenderDTOS);
        nextTimeDTOList1.addAll(nextTimeDTOList2);
        nextTimeDTOList2 = nextTimeDTOList1.stream()
                .sorted(Comparator.comparing(NextTimeDTO::getNextTime))
                .limit(5).collect(Collectors.toList());

        return new MensesCalenderNextTimeRespDTO(nextTimeDTOList2, calenderMonthDataDTOS);
    }


    public int[] getMonthDayArray(Date lastOneDate) {
        int[] monthDayArray = new int[42];
        int lastMonthMaxDay = DateUtil.endOfMonth(lastOneDate).dayOfMonth();
        int weekDay = DateUtil.dayOfWeek(DateUtil.beginOfMonth(lastOneDate));
        int nextMensesDateIndex = weekDay == 1 ? 6 : weekDay - 2;

        if (nextMensesDateIndex > 0) {
            Date lasMonth = DateUtil.offsetMonth(lastOneDate, -1);
            int dayIndex = DateUtil.endOfMonth(lasMonth).dayOfMonth();
            for (int i = 0; i < nextMensesDateIndex; i++) {
                monthDayArray[nextMensesDateIndex - i - 1] = dayIndex - i;
            }
        }

        int endIndex = 0;
        for (int i = nextMensesDateIndex; i < 42; i++) {
            monthDayArray[i] = i - nextMensesDateIndex + 1;
            if (monthDayArray[i] == lastMonthMaxDay) {
                monthDayArray[i + 1] = 1;
                endIndex = i + 1;
                break;
            }
        }

        for (int i = endIndex + 1; i < 42; i++) {
            monthDayArray[i] = monthDayArray[i - 1] + 1;
        }

        return monthDayArray;
    }

    private MensesCalenderMonthDataDTO changeToMensesCalender(int[] monthDayArray, Map<String, MensesCalenderDTO> calenderDTOMap, Date monthDay) {
        List<MensesCalenderDTO> mensesCalenders = new ArrayList<>();
        int counter = 0;
        for (int i = 0; i < monthDayArray.length; i++) {
            int day = monthDayArray[i];
            if (day == 1) {
                counter++;
            }
            if (counter == 0 || counter == 2) {
                int n = counter == 0 ? -1 : 1;
                String dayStr = DateUtil.format(DateUtil.offsetMonth(monthDay, n), "YYYY-MM");
                MensesCalenderDTO mensesCalender = calenderDTOMap.get(String.format("%s-%02d", dayStr, day));
                if (ObjectUtil.notNull(mensesCalender)) {
                    MensesCalenderDTO mensesCalenderDTO = new MensesCalenderDTO();
                    ObjectUtil.copyFieldValue(mensesCalender, mensesCalenderDTO);
                    mensesCalenderDTO.setType(MensesTypeEnum.DEFAULT.getName());
                    mensesCalenderDTO.setCssClass(MensesTypeEnum.DEFAULT.getCssClass());
                    mensesCalenderDTO.setIndex(i);
                    mensesCalenders.add(mensesCalenderDTO);
                }
            } else if (counter == 1) {
                String dayStr = DateUtil.format(monthDay, "YYYY-MM");
                MensesCalenderDTO mensesCalender = calenderDTOMap.get(String.format("%s-%02d", dayStr, day));
                if (ObjectUtil.notNull(mensesCalender)) {
                    MensesCalenderDTO mensesCalenderDTO = new MensesCalenderDTO();
                    ObjectUtil.copyFieldValue(mensesCalender, mensesCalenderDTO);
                    mensesCalenderDTO.setIndex(i);
                    mensesCalenders.add(mensesCalenderDTO);
                }
            }
        }

        return new MensesCalenderMonthDataDTO(DateUtil.format(monthDay, "YYYY-MM"), mensesCalenders);
    }

    public void getMensesCalenderDTO(int daysOfMensesDuration, Integer keepDateNum, Date nextMensesDate, int[] nextMonthDayArray, int[] nextNextMonthDayArray, List<MensesCalenderDTO> mensesCalenderDTOS, List<MensesCalenderDTO> nextMensesCalenderDTOS) {

        int startDayNumber = DateUtil.dayOfMonth(nextMensesDate);
        Date endMensesDate = DateUtil.offsetDay(nextMensesDate, daysOfMensesDuration);
        Date startOvulationDate = DateUtil.offsetDay(endMensesDate, -19); //下一个月经日的前19天是排卵期的开始日
        if (DateUtil.month(nextMensesDate) != DateUtil.month(startOvulationDate)) {
            startOvulationDate = DateUtil.offsetDay(startOvulationDate, -daysOfMensesDuration);
        }


        Date temp = DateUtil.date();
        Date tempNextMensesDate = nextMensesDate;
        while (DateUtil.month(tempNextMensesDate) == DateUtil.month(temp)) {
            for (int i = 0; i < keepDateNum; i++) {
                Date offsetDay = DateUtil.offsetDay(tempNextMensesDate, i);
                int day = DateUtil.dayOfMonth(offsetDay);
                MensesCalenderDTO mensesCalenderDTO = new MensesCalenderDTO();
                mensesCalenderDTO.setDayNumber(day);
                mensesCalenderDTO.setDay(offsetDay);

                if (i == 0) {
                    mensesCalenderDTO.setType(MensesTypeEnum.MENSES_DAY.getName());
                    mensesCalenderDTO.setCssClass(MensesTypeEnum.MENSES_DAY.getCssClass());
                } else {
                    mensesCalenderDTO.setType(MensesTypeEnum.MENSES.getName());
                    mensesCalenderDTO.setCssClass(MensesTypeEnum.MENSES.getCssClass());
                }

                if (day < startDayNumber) {
                    if (ObjectUtil.notNull(nextNextMonthDayArray)) {
                        int index = getIndexByDayNumber(nextNextMonthDayArray, day);
                        mensesCalenderDTO.setIndex(index);
                        nextMensesCalenderDTOS.add(mensesCalenderDTO);
                    }
                } else {
                    if (ObjectUtil.notNull(nextMonthDayArray)) {
                        int index = getIndexByDayNumber(nextMonthDayArray, day);
                        mensesCalenderDTO.setIndex(index);
                        mensesCalenderDTOS.add(mensesCalenderDTO);
                    }
                }

            }
            tempNextMensesDate = DateUtil.offsetDay(tempNextMensesDate, -daysOfMensesDuration);
        }

        Date tempStartOvulationDate = startOvulationDate;
        while (DateUtil.month(tempStartOvulationDate) == DateUtil.month(temp)) {
            for (int i = 0; i < 10; i++) {
                Date offsetDay = DateUtil.offsetDay(tempStartOvulationDate, i);
                int day = DateUtil.dayOfMonth(offsetDay);
                MensesCalenderDTO mensesCalenderDTO = new MensesCalenderDTO();
                if (i == 5) {
                    mensesCalenderDTO.setType(MensesTypeEnum.OVULATION_DAY.getName());
                    mensesCalenderDTO.setCssClass(MensesTypeEnum.OVULATION_DAY.getCssClass());
                } else if (i == 0) {
                    mensesCalenderDTO.setType(MensesTypeEnum.OVULATION_START_DAY.getName());
                    mensesCalenderDTO.setCssClass(MensesTypeEnum.OVULATION_START_DAY.getCssClass());
                } else {
                    mensesCalenderDTO.setType(MensesTypeEnum.OVULATION.getName());
                    mensesCalenderDTO.setCssClass(MensesTypeEnum.OVULATION.getCssClass());
                }

                mensesCalenderDTO.setDayNumber(day);
                mensesCalenderDTO.setDay(offsetDay);
                if (DateUtil.month(nextMensesDate) != DateUtil.month(offsetDay)) {
                    if (ObjectUtil.notNull(nextNextMonthDayArray)) {
                        int index = getIndexByDayNumber(nextNextMonthDayArray, day);
                        mensesCalenderDTO.setIndex(index);
                        nextMensesCalenderDTOS.add(mensesCalenderDTO);
                    }
                } else {
                    if (ObjectUtil.notNull(nextMonthDayArray)) {
                        int index = getIndexByDayNumber(nextMonthDayArray, day);
                        mensesCalenderDTO.setIndex(index);
                        mensesCalenderDTOS.add(mensesCalenderDTO);
                    }
                }
            }
            tempStartOvulationDate = DateUtil.offsetDay(tempStartOvulationDate, -daysOfMensesDuration);
        }
    }

    public Map<String, MensesCalenderDTO> findMensesTipDateCalenderData(MensesRemindTask mensesRemindTask) throws Exception {
        int daysOfMensesDuration = (int) DateUtil.betweenDay(mensesRemindTask.getMensesLastDateOne(), mensesRemindTask.getMensesLastDateTwo(), true);
        if (daysOfMensesDuration < 15) {
            throw new BusinessException("非正常月经周期");
        }
        Date mensesDate = mensesRemindTask.getMensesLastDateOne();
        Date now = DateUtil.date();

        while (mensesDate.before(now)) {
            mensesDate = DateUtil.offsetDay(mensesDate, daysOfMensesDuration);
        }

        mensesDate = DateUtil.offsetDay(mensesDate, -daysOfMensesDuration);
        int keepDayNum = mensesRemindTask.getMensesKeepDateNum();
        Map<String, MensesCalenderDTO> dateMapData = new HashMap<>();
        Date startDate = DateUtil.beginOfMonth(DateUtil.offsetMonth(mensesDate, -2));
        Date endDate = DateUtil.endOfMonth(DateUtil.offsetMonth(mensesDate, 2));
        List<DateTime> dates = DateUtil.rangeToList(startDate, endDate, DateField.DAY_OF_MONTH);

        for (DateTime date : dates) {
            MensesCalenderDTO mensesCalenderDTO = new MensesCalenderDTO();
            mensesCalenderDTO.setDayNumber(DateUtil.dayOfMonth(date));
            mensesCalenderDTO.setDay(date);
            long n = DateUtil.betweenDay(mensesDate, date, true);
            long l = n % daysOfMensesDuration;
            if (l == 0) {
                if (mensesRemindTask.getIsMensesStartDateAlter()) {
                    if (mensesRemindTask.getIsMensesStartDateAlter1()) {
                        setTipDateTime(mensesRemindTask.getMensesDayTime(), mensesCalenderDTO);
                    } else if (mensesRemindTask.getIsMensesStartDateAlter2()) {
                        Date preDate = DateUtil.offsetDay(date, -1);
                        MensesCalenderDTO preCalenderDay = dateMapData.get(DateUtil.formatDate(preDate));
                        if (ObjectUtil.notNull(preCalenderDay)) {
                            setTipDateTime(mensesRemindTask.getMensesPrevDayTime(), preCalenderDay);
                        }
                    }
                }

                mensesCalenderDTO.setType(MensesTypeEnum.MENSES_DAY.getName());
                mensesCalenderDTO.setCssClass(MensesTypeEnum.MENSES_DAY.getCssClass());
                dateMapData.put(DateUtil.formatDate(date), mensesCalenderDTO);

                for (int i = 1; i < keepDayNum; i++) {
                    Date nextDate = DateUtil.offsetDay(date, i);
                    MensesCalenderDTO mensesCalender = new MensesCalenderDTO();
                    mensesCalender.setDayNumber(DateUtil.dayOfMonth(nextDate));
                    mensesCalender.setDay(nextDate);
                    mensesCalender.setType(MensesTypeEnum.MENSES.getName());
                    mensesCalender.setCssClass(MensesTypeEnum.MENSES.getCssClass());
                    dateMapData.put(DateUtil.formatDate(nextDate), mensesCalender);
                }
                continue;
            }

            //排卵日开始日
            Date startOvulationDate = DateUtil.offsetDay(mensesDate, daysOfMensesDuration - 19);
            n = DateUtil.betweenDay(startOvulationDate, date, true);
            l = n % daysOfMensesDuration;
            if (l == 0) {
                if (mensesRemindTask.getIsOvulationDateAlter()) {
                    if (mensesRemindTask.getIsOvulationDateAlter1()) {
                        setTipDateTime(mensesRemindTask.getOvulationDayTime(), mensesCalenderDTO);
                    } else if (mensesRemindTask.getIsOvulationDateAlter2()) {
                        Date preDate = DateUtil.offsetDay(date, -1);
                        MensesCalenderDTO preCalenderDay = dateMapData.get(DateUtil.formatDate(preDate));
                        if (ObjectUtil.notNull(preCalenderDay)) {
                            setTipDateTime(mensesRemindTask.getOvulationPrevDayTime(), preCalenderDay);
                        }
                    }
                }

                mensesCalenderDTO.setType(MensesTypeEnum.OVULATION_START_DAY.getName());
                mensesCalenderDTO.setCssClass(MensesTypeEnum.OVULATION_START_DAY.getCssClass());
                MensesCalenderDTO calenderDTO = MapUtil.get(dateMapData, DateUtil.formatDate(date), MensesCalenderDTO.class);
                if (ObjectUtil.isNull(calenderDTO)
                        || (!calenderDTO.getType().equals(MensesTypeEnum.MENSES.getName())
                        && !calenderDTO.getType().equals(MensesTypeEnum.MENSES_DAY.getName()))) {
                    dateMapData.put(DateUtil.formatDate(date), mensesCalenderDTO);
                }

                for (int i = 1; i < 10; i++) {
                    Date nextDate = DateUtil.offsetDay(date, i);
                    MensesCalenderDTO mensesCalender = new MensesCalenderDTO();
                    mensesCalender.setDayNumber(DateUtil.dayOfMonth(nextDate));
                    mensesCalender.setDay(nextDate);
                    if (i == 5) {
                        mensesCalender.setType(MensesTypeEnum.OVULATION_DAY.getName());
                        mensesCalender.setCssClass(MensesTypeEnum.OVULATION_DAY.getCssClass());
                    } else {
                        mensesCalender.setType(MensesTypeEnum.OVULATION.getName());
                        mensesCalender.setCssClass(MensesTypeEnum.OVULATION.getCssClass());
                    }
                    String dateStr = DateUtil.formatDate(nextDate);
                    calenderDTO = MapUtil.get(dateMapData, dateStr, MensesCalenderDTO.class);

                    if (ObjectUtil.isNull(calenderDTO)
                            || (!calenderDTO.getType().equals(MensesTypeEnum.MENSES.getName())
                            && !calenderDTO.getType().equals(MensesTypeEnum.MENSES_DAY.getName()))) {
                        dateMapData.put(dateStr, mensesCalender);
                    }
                }
                continue;
            }

            MensesCalenderDTO dayCalender = dateMapData.get(DateUtil.formatDate(date));
            MensesCalenderDTO temp = dateMapData.get(DateUtil.formatDate(DateUtil.offsetDay(date, -1)));
            if (ObjectUtil.notNull(temp) && ObjectUtil.isNull(dayCalender)
                    && !temp.getType().equals(MensesTypeEnum.SAFE_DAY.getName())
                    && !temp.getType().equals(MensesTypeEnum.SAFE_START_DAY.getName())
            ) {
                if (mensesRemindTask.getIsSafeDateAlter()) {
                    if (mensesRemindTask.getIsSafeDateAlter1()) {
                        setTipDateTime(mensesRemindTask.getSafeDateDayTime(), mensesCalenderDTO);
                    } else if (mensesRemindTask.getIsSafeDateAlter2()) {
                        Date preDate = DateUtil.offsetDay(date, -1);
                        MensesCalenderDTO preCalenderDay = dateMapData.get(DateUtil.formatDate(preDate));
                        if (ObjectUtil.notNull(preCalenderDay)) {
                            setTipDateTime(mensesRemindTask.getSafeDatePrevDayTime(), preCalenderDay);
                        }
                    }
                }

                mensesCalenderDTO.setType(MensesTypeEnum.SAFE_START_DAY.getName());
                mensesCalenderDTO.setCssClass(MensesTypeEnum.SAFE_START_DAY.getCssClass());
                dateMapData.put(DateUtil.formatDate(date), mensesCalenderDTO);
            } else if (ObjectUtil.isNull(dayCalender)) {
                mensesCalenderDTO.setType(MensesTypeEnum.SAFE_DAY.getName());
                mensesCalenderDTO.setCssClass(MensesTypeEnum.SAFE_DAY.getCssClass());
                dateMapData.put(DateUtil.formatDate(date), mensesCalenderDTO);
            }


        }

        return dateMapData;

    }

    private int getIndexByDayNumber(int[] monthDayArray, int dayNumber) {
        int count = 0;
        for (int i = 0; i < monthDayArray.length; i++) {
            if (monthDayArray[i] == 1) {
                count++;
                if (dayNumber == 1) {
                    return i;
                }
            } else if (count > 0 && dayNumber == monthDayArray[i]) {
                return i;
            }
        }
        return 0;
    }

    private void fillSafeDaysAndDefaultDay(int[] nextMonthDayArray, List<MensesCalenderDTO> mensesCalenderDTOS, Date nextMensesDate) {
        List<MensesCalenderDTO> temp = new ArrayList<>();
        int count = 0;
        for (int i = 0; i < nextMonthDayArray.length; i++) {
            int day = nextMonthDayArray[i];
            int j = i;
            boolean flag = mensesCalenderDTOS.stream().filter(p -> p.getDayNumber() == day && j == p.getIndex()).findFirst().isPresent();
            if (day == 1) {
                count++;
            }
            if (!flag) {
                MensesCalenderDTO mensesCalenderDTO = new MensesCalenderDTO();
                mensesCalenderDTO.setDayNumber(day);
                mensesCalenderDTO.setIndex(i);


                if (count == 0 || count == 2) {
                    Date offsetDay;
                    mensesCalenderDTO.setType(MensesTypeEnum.DEFAULT.getName());
                    mensesCalenderDTO.setCssClass(MensesTypeEnum.DEFAULT.getCssClass());
                    if (count == 0) {
                        offsetDay = DateUtil.parseDate(String.format("%s-%02d", DateUtil.format(DateUtil.offsetMonth(nextMensesDate, -1), "YYYY-MM"), day));
                    } else {
                        offsetDay = DateUtil.parseDate(String.format("%s-%02d", DateUtil.format(DateUtil.offsetMonth(nextMensesDate, 1), "YYYY-MM"), day));
                    }
                    mensesCalenderDTO.setDay(offsetDay);
                } else if (count == 1) {
                    flag = mensesCalenderDTOS.stream().filter(p -> !p.getType().equals(MensesTypeEnum.SAFE_DAY.getName()) && j - 1 == p.getIndex()).findFirst().isPresent();
                    if (flag) {
                        mensesCalenderDTO.setType(MensesTypeEnum.SAFE_START_DAY.getName());
                        mensesCalenderDTO.setCssClass(MensesTypeEnum.SAFE_START_DAY.getCssClass());
                    } else {
                        mensesCalenderDTO.setType(MensesTypeEnum.SAFE_DAY.getName());
                        mensesCalenderDTO.setCssClass(MensesTypeEnum.SAFE_DAY.getCssClass());
                    }
                    Date offsetDay = DateUtil.parseDate(String.format("%s-%02d", DateUtil.format(nextMensesDate, "YYYY-MM"), day));
                    mensesCalenderDTO.setDay(offsetDay);
                }
                temp.add(mensesCalenderDTO);
            }
        }
        mensesCalenderDTOS.addAll(temp);


    }

    private void analysisRemindDay(MensesRemindTask mensesRemindTask, List<MensesCalenderDTO> mensesCalenderDTOS) {
        Date nowDate = DateUtil.date();
        Date nextMensesDate = mensesRemindTask.getMensesLastDateOne();
        Date lastTwoDate = mensesRemindTask.getMensesLastDateTwo();
        int daysOfMensesDuration = (int) DateUtil.betweenDay(nextMensesDate, lastTwoDate, true);
        for (int i = 0; i < mensesCalenderDTOS.size(); i++) {
            MensesCalenderDTO mensesCalenderDTO = mensesCalenderDTOS.get(i);
            if (mensesRemindTask.getIsMensesStartDateAlter() && mensesCalenderDTO.getType().equals(MensesTypeEnum.MENSES_DAY.getName())) {
                if (mensesRemindTask.getIsMensesStartDateAlter1()) {
                    //设置小时分钟
                    setTipDateTime(mensesRemindTask.getMensesDayTime(), mensesCalenderDTO);
                    if (DateUtil.compare(nowDate, mensesCalenderDTO.getDay()) < 0) {
                        mensesCalenderDTO.setIsRemind(true);
                        mensesCalenderDTO.setRemark(RemindConstant.MENSES_DAY);
                    }
                }
                if (mensesRemindTask.getIsMensesStartDateAlter2()) {
                    mensesCalenderDTO = mensesCalenderDTOS.get(i - 1);
                    //设置小时分钟
                    setTipDateTime(mensesRemindTask.getMensesPrevDayTime(), mensesCalenderDTO);
                    if (DateUtil.compare(nowDate, mensesCalenderDTO.getDay()) < 0) {
                        if (i > 0) {
                            mensesCalenderDTOS.get(i - 1).setIsRemind(true);
                            mensesCalenderDTO.setRemark(RemindConstant.MENSES_PRE_DAY);
                        }
                        checkLastDayIsRemind(mensesCalenderDTO, mensesCalenderDTOS, daysOfMensesDuration);
                    }
                }
            }
            if (mensesRemindTask.getIsOvulationDateAlter() && mensesCalenderDTO.getType().equals(MensesTypeEnum.OVULATION_DAY.getName())) {
                if (mensesRemindTask.getIsOvulationDateAlter1()) {
                    //设置小时分钟
                    setTipDateTime(mensesRemindTask.getOvulationDayTime(), mensesCalenderDTO);
                    if (DateUtil.compare(nowDate, mensesCalenderDTO.getDay()) < 0) {
                        mensesCalenderDTO.setIsRemind(true);
                        mensesCalenderDTO.setRemark(RemindConstant.MENSES_OVULATION_DAY);
                    }
                }
                if (mensesRemindTask.getIsOvulationDateAlter2()) {
                    mensesCalenderDTO = mensesCalenderDTOS.get(i - 1);
                    //设置小时分钟
                    setTipDateTime(mensesRemindTask.getOvulationPrevDayTime(), mensesCalenderDTO);
                    if (DateUtil.compare(nowDate, mensesCalenderDTO.getDay()) < 0) {
                        if (i > 0) {
                            mensesCalenderDTOS.get(i - 1).setIsRemind(true);
                            mensesCalenderDTO.setRemark(RemindConstant.MENSES_OVULATION_PRE_DAY);
                        }
                        checkLastDayIsRemind(mensesCalenderDTO, mensesCalenderDTOS, daysOfMensesDuration);
                    }
                }
            }
            if (mensesRemindTask.getIsSafeDateAlter() && mensesCalenderDTO.getType().equals(MensesTypeEnum.SAFE_START_DAY.getName())) {
                if (mensesRemindTask.getIsSafeDateAlter1()) {
                    //设置小时分钟
                    setTipDateTime(mensesRemindTask.getSafeDateDayTime(), mensesCalenderDTO);
                    if (DateUtil.compare(nowDate, mensesCalenderDTO.getDay()) < 0) {
                        mensesCalenderDTO.setIsRemind(true);
                        mensesCalenderDTO.setRemark(RemindConstant.MENSES_SAFE_DAY);
                    }
                }
                if (mensesRemindTask.getIsSafeDateAlter2()) {
                    mensesCalenderDTO = mensesCalenderDTOS.get(i - 1);
                    //设置小时分钟
                    setTipDateTime(mensesRemindTask.getSafeDatePrevDayTime(), mensesCalenderDTO);
                    if (DateUtil.compare(nowDate, mensesCalenderDTO.getDay()) < 0) {
                        if (i > 0) {
                            mensesCalenderDTOS.get(i - 1).setIsRemind(true);
                            mensesCalenderDTO.setRemark(RemindConstant.MENSES_SAFE_PRE_DAY);
                        }
                        checkLastDayIsRemind(mensesCalenderDTO, mensesCalenderDTOS, daysOfMensesDuration);
                    }
                }
            }
            if (mensesRemindTask.getIsOvulationDurationAlter() && mensesCalenderDTO.getType().equals(MensesTypeEnum.OVULATION_START_DAY.getName())) {
                if (mensesRemindTask.getIsOvulationDurationAlter1()) {
                    //设置小时分钟
                    setTipDateTime(mensesRemindTask.getOvulationDurationDayTime(), mensesCalenderDTO);
                    if (DateUtil.compare(nowDate, mensesCalenderDTO.getDay()) < 0) {
                        mensesCalenderDTO.setIsRemind(true);
                        mensesCalenderDTO.setRemark(RemindConstant.MENSES_OVULATION_DURATION_DAY);
                    }
                }
                if (mensesRemindTask.getIsOvulationDurationAlter2()) {
                    mensesCalenderDTO = mensesCalenderDTOS.get(i - 1);
                    //设置小时分钟
                    setTipDateTime(mensesRemindTask.getOvulationDurationPrevDayTime(), mensesCalenderDTO);
                    if (DateUtil.compare(nowDate, mensesCalenderDTO.getDay()) < 0) {
                        if (i > 0) {
                            mensesCalenderDTOS.get(i - 1).setIsRemind(true);
                            mensesCalenderDTO.setRemark(RemindConstant.MENSES_OVULATION_DURATION_PRE_DAY);
                        }
                        checkLastDayIsRemind(mensesCalenderDTO, mensesCalenderDTOS, daysOfMensesDuration);
                    }
                }
            }
        }

    }

    private List<NextTimeDTO> getNextTimeDTOList(List<MensesCalenderDTO> mensesCalenderDTOS) {
        return mensesCalenderDTOS.stream()
                .filter(p -> ObjectUtil.notNull(p.getIsRemind()) && p.getIsRemind())
                .map(MensesCalenderDTO::changeToNextTimeDTO).collect(Collectors.toList());
    }

    public void checkLastDayIsRemind(MensesCalenderDTO mensesCalenderDTO, List<MensesCalenderDTO> mensesCalenderDTOS, int daysOfMensesDuration) {
        Date d = DateUtil.offsetDay(mensesCalenderDTO.getDay(), daysOfMensesDuration);
        int n = 1;
        Date endDayOfMonth = DateUtil.endOfMonth(mensesCalenderDTO.getDay());
        while (DateUtil.compare(d, endDayOfMonth) < 0) {
            d = DateUtil.offsetDay(mensesCalenderDTO.getDay(), daysOfMensesDuration * n++);
        }
        if (DateUtil.dayOfMonth(d) == 1) {
            mensesCalenderDTOS.stream()
                    .filter(p -> !p.getType().equals(MensesTypeEnum.DEFAULT.getName()))
                    .max(Comparator.comparing(MensesCalenderDTO::getIndex))
                    .get().setIsRemind(true);
        }
    }

    private void setTipDateTime(String timeHour, MensesCalenderDTO mensesCalenderDTO) {
        Date day = mensesCalenderDTO.getDay();
        String dateStr = String.format("%s %s:00", DateUtil.formatDate(day), timeHour);
        mensesCalenderDTO.setDay(DateUtil.parseDateTime(dateStr));
    }


    @Override
    public void beforeSave(MensesRemindTask domain) throws Exception {
        String unicode = WebUtil.getLoginUser().getUuid();
        RemindType remindType = remindTypeService.queryTypeByName(RemindTypeEnum.MENSTRUATION.getName(), unicode);
        domain.setRemindType(remindType);
        domain.setUnicode(unicode);
    }

    @Override
    public void afterSave(MensesRemindTask domain) throws Exception {

        //注销额外定时任务
        extraJobCronService.cancelMensesExtraJob(domain.getId());

        //生成额外定时任务
        extraJobCronService.generateMensesExtraJob(domain);

    }

    @Override
    public void afterDelete(MensesRemindTask domain) throws Exception {
        //注销额外定时任务
        extraJobCronService.cancelMensesExtraJob(domain.getId());
    }
}



